package info.webest.media.activities;

import info.webest.media.Options;
import info.webest.media.R;
import info.webest.media.visualizer.VisualizerView;
import info.webest.media.visualizer.renderer.BarGraphRenderer;
import info.webest.media.visualizer.renderer.CircleBarRenderer;
import info.webest.media.visualizer.renderer.CircleRenderer;
import info.webest.media.visualizer.renderer.LineRenderer;

import java.util.ArrayList;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.media.audiofx.BassBoost;
import android.media.audiofx.Equalizer;
import android.media.audiofx.Visualizer;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.Spinner;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;

@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public class EqualizerActivity extends Activity implements
		OnItemSelectedListener, SeekBar.OnSeekBarChangeListener,
		CompoundButton.OnCheckedChangeListener {

	int audioSessionId = 0;

	private static final float VISUALIZER_HEIGHT_DIP = 50f;
	private static final float VISUALIZER_WIDHT_DIP = (8 + 3) * 16;

	private Visualizer mVisualizer;
	private RelativeLayout mVisualizerLayout;
	private VisualizerView mVisualizerView;

	float density = 0;

	String PREF_EQUALIZER = "EqualizerSettings";

	TextView bass_boost_label = null;
	SeekBar bass_boost = null;

	ToggleButton toggleEqualizer = null;
	Switch switcherEqualizer = null;

	Spinner spEqualizer = null;
	ArrayList<CharSequence> listEqualizer = new ArrayList<CharSequence>();

	Equalizer eq = null;
	BassBoost bb = null;

	int min_level = 0;
	int max_level = 100;

	static final int MAX_SLIDERS = 8; // Must match the XML layout
	SeekBar sliders[] = new SeekBar[MAX_SLIDERS];
	TextView slider_labels[] = new TextView[MAX_SLIDERS];
	int num_sliders = 0;

	@Override
	public void onBackPressed() {
		// super.onBackPressed();
		Intent intent = new Intent();
		// intent.putExtra("RefreshUI", RefreshUI);
		setResult(RESULT_OK, intent);
		finish();
	}

	/*
	 * ==========================================================================
	 * === onCreate
	 * ==============================================================
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// MenuInflater inflater = getMenuInflater();
		// inflater.inflate(R.menu.main_menu, menu);
		return true;
	}

	/*
	 * ==========================================================================
	 * === onCreate
	 * ==============================================================
	 */
	@SuppressLint("NewApi")
	@Override
	public void onCreate(Bundle savedInstanceState) {
		// Theme
		setTheme(Options.getThemeId());

		if (Options.ShowWhenLocked) {
			getWindow().addFlags(
					WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
		} else {
			getWindow().clearFlags(
					WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
		}

		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_equalizer);

		density = getResources().getDisplayMetrics().density;

		Bundle extras = getIntent().getExtras();

		if (extras != null && extras.containsKey("audioSessionId")) {
			audioSessionId = extras.getInt("audioSessionId");
		}

		mVisualizerLayout = (RelativeLayout) findViewById(R.id.ltVisualizer);

		bass_boost = (SeekBar) findViewById(R.id.bass_boost);
		bass_boost.setOnSeekBarChangeListener(this);

		if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH) {
			switcherEqualizer = (Switch) findViewById(R.id.switcherEqualizer);
			switcherEqualizer.setOnCheckedChangeListener(this);
		} else {
			bass_boost_label = (TextView) findViewById(R.id.bass_boost_label);
			toggleEqualizer = (ToggleButton) findViewById(R.id.toggleEqualizer);
			toggleEqualizer.setOnCheckedChangeListener(this);
		}

		sliders[0] = (SeekBar) findViewById(R.id.slider_1);
		slider_labels[0] = (TextView) findViewById(R.id.slider_label_1);
		sliders[1] = (SeekBar) findViewById(R.id.slider_2);
		slider_labels[1] = (TextView) findViewById(R.id.slider_label_2);
		sliders[2] = (SeekBar) findViewById(R.id.slider_3);
		slider_labels[2] = (TextView) findViewById(R.id.slider_label_3);
		sliders[3] = (SeekBar) findViewById(R.id.slider_4);
		slider_labels[3] = (TextView) findViewById(R.id.slider_label_4);
		sliders[4] = (SeekBar) findViewById(R.id.slider_5);
		slider_labels[4] = (TextView) findViewById(R.id.slider_label_5);
		sliders[5] = (SeekBar) findViewById(R.id.slider_6);
		slider_labels[5] = (TextView) findViewById(R.id.slider_label_6);
		sliders[6] = (SeekBar) findViewById(R.id.slider_7);
		slider_labels[6] = (TextView) findViewById(R.id.slider_label_7);
		sliders[7] = (SeekBar) findViewById(R.id.slider_8);
		slider_labels[7] = (TextView) findViewById(R.id.slider_label_8);

		eq = new Equalizer(0, audioSessionId);
		if (eq != null) {

			SharedPreferences pref = PreferenceManager
					.getDefaultSharedPreferences(this);

			Equalizer.Settings settings = new Equalizer.Settings(
					pref.getString(PREF_EQUALIZER, eq.getProperties()
							.toString()));

			eq.setProperties(settings);

			eq.setEnabled(true);
			int num_bands = eq.getNumberOfBands();
			num_sliders = num_bands;
			short r[] = eq.getBandLevelRange();
			min_level = r[0];
			max_level = r[1];
			for (int i = 0; i < num_sliders && i < MAX_SLIDERS; i++) {
				int[] freq_range = eq.getBandFreqRange((short) i);
				// sliders[i].setOnSeekBarChangeListener(this);
				slider_labels[i].setText(formatBandLabel(freq_range));
			}
		}
		for (int i = num_sliders; i < MAX_SLIDERS; i++) {
			sliders[i].setVisibility(View.GONE);
			slider_labels[i].setVisibility(View.GONE);
		}

		bb = new BassBoost(0, audioSessionId);
		if (bb != null) {
		} else {
			bass_boost.setVisibility(View.GONE);

			if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH) {

			} else {
				bass_boost_label.setVisibility(View.GONE);
			}
		}

		spEqualizer = (Spinner) findViewById(R.id.spEqualizer);

		for (short i = 0; i < eq.getNumberOfPresets(); i++) {
			listEqualizer.add(eq.getPresetName(i).toString());
		}

		// Create an ArrayAdapter using the string array and a default spinner
		// layout

		ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(
				this, R.layout.spinner_header, listEqualizer) {

			// int normalTextSize = 15;

			// @Override
			// public View getView(int position, View convertView, ViewGroup
			// parent) {
			// View v = super.getView(position, convertView, parent);
			// if (v instanceof TextView)
			// ((TextView) v).setTextSize(TypedValue.COMPLEX_UNIT_PX,
			// normalTextSize);
			// return v;
			// }

			// @Override
			// public View getDropDownView(int position, View convertView,
			// ViewGroup parent) {
			// View v = super.getDropDownView(position, convertView, parent);
			// if (v instanceof TextView)
			// ((TextView) v).setTextSize(TypedValue.COMPLEX_UNIT_PX,
			// normalTextSize);
			// return v;
			// }
		};
		// Specify the layout to use when the list of choices appears
		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		// Apply the adapter to the spinner
		spEqualizer.setAdapter(adapter);
		short preset = eq.getCurrentPreset();
		if (preset != -1) {
			spEqualizer.setSelection(preset);
		}
		spEqualizer.setOnItemSelectedListener(this);

		setupVisualizerFxAndUI();
		// Make sure the visualizer is enabled only when you actually want to
		// receive data, and when it makes sense to receive data.
		mVisualizer.setEnabled(true);

		updateUI();
		setSeekBarChangeListener(this);
	}

	public void setSeekBarChangeListener(SeekBar.OnSeekBarChangeListener I) {
		for (int i = 0; i < num_sliders && i < MAX_SLIDERS; i++) {
			sliders[i].setOnSeekBarChangeListener(I);
		}
	}

	@Override
	public void onStop() {
		if (eq != null) {

			SharedPreferences pref = PreferenceManager
					.getDefaultSharedPreferences(this);

			SharedPreferences.Editor editor = pref.edit();
			String s = eq.getProperties().toString();
			editor.putString(PREF_EQUALIZER, s);
			editor.commit();
		}
		super.onStop();
	}

	/*
	 * ==========================================================================
	 * === onProgressChanged
	 * ====================================================
	 */
	@Override
	public void onProgressChanged(SeekBar seekBar, int level, boolean fromTouch) {
		if (seekBar == bass_boost) {
			bb.setEnabled(level > 0 ? true : false);
			bb.setStrength((short) level); // Already in the right range 0-1000
		} else if (eq != null) {
			int new_level = min_level + (max_level - min_level) * level / 100;

			for (int i = 0; i < num_sliders; i++) {
				if (sliders[i] == seekBar) {
					eq.setBandLevel((short) i, (short) new_level);
					break;
				}
			}
		}
	}

	/*
	 * ==========================================================================
	 * === onStartTrackingTouch
	 * ==================================================
	 */
	@Override
	public void onStartTrackingTouch(SeekBar seekBar) {
	}

	/*
	 * ==========================================================================
	 * === onStopTrackingTouch
	 * ==================================================
	 */
	@Override
	public void onStopTrackingTouch(SeekBar seekBar) {
	}

	/*
	 * ==========================================================================
	 * === formatBandLabel
	 * ======================================================
	 */
	public String formatBandLabel(int[] band) {
		return milliHzToString(band[0]) + "-" + milliHzToString(band[1]);
	}

	/*
	 * ==========================================================================
	 * === milliHzToString
	 * ======================================================
	 */
	public String milliHzToString(int milliHz) {
		if (milliHz < 1000)
			return "";
		if (milliHz < 1000000)
			return "" + (milliHz / 1000) + "Hz";
		else
			return "" + (milliHz / 1000000) + "kHz";
	}

	/*
	 * ==========================================================================
	 * === updateSliders
	 * ========================================================
	 */
	public void updateSliders() {
		for (int i = 0; i < num_sliders; i++) {
			int level;
			if (eq != null)
				level = eq.getBandLevel((short) i);
			else
				level = 0;
			int pos = 100 * level / (max_level - min_level) + 50;
			sliders[i].setProgress(pos);
			sliders[i].setSecondaryProgress(0);
		}
	}

	/*
	 * ==========================================================================
	 * === updateBassBoost
	 * ======================================================
	 */
	public void updateBassBoost() {
		if (bb != null)
			bass_boost.setProgress(bb.getRoundedStrength());
		else
			bass_boost.setProgress(0);
	}

	/*
	 * ==========================================================================
	 * === onCheckedChange
	 * ======================================================
	 */
	@Override
	public void onCheckedChanged(CompoundButton view, boolean isChecked) {

		if (view == (View) switcherEqualizer) {
			eq.setEnabled(isChecked);
		}
	}

	/*
	 * ==========================================================================
	 * === onClick
	 * ==============================================================
	 */
	// @Override
	// public void onClick(View view) {
	// if (view == (View) flat) {
	// setFlat();
	// }
	// }

	/*
	 * ==========================================================================
	 * === updateUI
	 * ==============================================================
	 */
	@SuppressLint("NewApi")
	public void updateUI() {
		updateSliders();
		updateBassBoost();

		if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH) {
			switcherEqualizer.setChecked(eq.getEnabled());
		} else {
			toggleEqualizer.setChecked(eq.getEnabled());
		}

	}

	/*
	 * ==========================================================================
	 * === setFlat
	 * ==============================================================
	 * 
	 * public void setFlat() { if (eq != null) { for (int i = 0; i <
	 * num_sliders; i++) { eq.setBandLevel((short) i, (short) 0); }
	 * 
	 * short preset = eq.getCurrentPreset(); if (preset != -1) {
	 * eq.usePreset(preset); spEqualizer.setSelection(preset); } }
	 * 
	 * if (bb != null) { bb.setEnabled(false); bb.setStrength((short) 0); }
	 * updateUI(); }
	 */

	@Override
	public void onItemSelected(AdapterView<?> parent, View view, int position,
			long id) {

		String s = eq.getProperties().toString();
		eq.usePreset((short) position);
		s = eq.getProperties().toString();
		try {
			setSeekBarChangeListener(null); // off
			updateUI();
		} catch (Exception e) {
			setSeekBarChangeListener(this);// on
		}

		// Get the currently selected State object from the spinner
		s = (String) spEqualizer.getSelectedItem();

		// Show it via a toast
		Toast.makeText(getApplicationContext(), "Selected: " + s,
				Toast.LENGTH_SHORT).show();
	}

	@Override
	public void onNothingSelected(AdapterView<?> arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	protected void onPause() {
		super.onPause();
		if (isFinishing()) {
			mVisualizer.release();
			// mEqualizer.release();
			// mMediaPlayer.release();
			// mMediaPlayer = null;
		}
	}

	private void setupVisualizerFxAndUI() {
		// Create a VisualizerView (defined below), which will render the
		// simplified audio
		// wave form to a Canvas.

		// mVisualizerView = (VisualizerView) findViewById(R.id.visualizerView);
		// mVisualizerView.link(mPlayer);

		mVisualizerView = new VisualizerView(this);
		mVisualizerView.setLayoutParams(new ViewGroup.LayoutParams(
				(int) (VISUALIZER_WIDHT_DIP * density),
				// ViewGroup.LayoutParams.MATCH_PARENT,
				(int) (VISUALIZER_HEIGHT_DIP * density)));
		mVisualizerView.setBackgroundColor(getResources().getColor(
				android.R.color.darker_gray));
		mVisualizerLayout.addView(mVisualizerView);

		// Create the Visualizer object and attach it to our media player.
		mVisualizer = new Visualizer(audioSessionId);
		mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);

		// Pass through Visualizer data to VisualizerView
		mVisualizer.setDataCaptureListener(
				new Visualizer.OnDataCaptureListener() {
					public void onWaveFormDataCapture(Visualizer visualizer,
							byte[] bytes, int samplingRate) {
						mVisualizerView.updateVisualizer(bytes);
					}

					public void onFftDataCapture(Visualizer visualizer,
							byte[] bytes, int samplingRate) {
						mVisualizerView.updateVisualizerFFT(bytes);
					}
				}, Visualizer.getMaxCaptureRate() / 2, true, true);

		// Enabled Visualizer and disable when we're done with the stream
		mVisualizer.setEnabled(true);

		/*
		 * player.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
		 * {
		 * 
		 * @Override public void onCompletion(MediaPlayer mediaPlayer) {
		 * mVisualizer.setEnabled(false); } });
		 */

		// mVisualizerView.clearRenderers();
		addBarGraphRenderers();
	}

	// Methods for adding renderers to visualizer
	private void addBarGraphRenderers() {
		/*
		 * Paint paint = new Paint(); paint.setStrokeWidth(15);
		 * paint.setAntiAlias(true); paint.setColor(Color.argb(200, 56, 138,
		 * 252)); BarGraphRenderer barGraphRendererBottom = new
		 * BarGraphRenderer(8, paint, false);
		 * mVisualizerView.addRenderer(barGraphRendererBottom);
		 */

		Paint paint = new Paint();
		paint.setStrokeWidth((int) (8 * density));
		paint.setAntiAlias(true);
		paint.setColor(Color.argb(200, 56, 138, 252));
		BarGraphRenderer barGraphRendererBottom = new BarGraphRenderer(5,
				paint, false);
		mVisualizerView.addRenderer(barGraphRendererBottom);
		/*
		 * Paint paint2 = new Paint(); paint2.setStrokeWidth(12f);
		 * paint2.setAntiAlias(true); paint2.setColor(Color.argb(200, 181, 111,
		 * 233)); BarGraphRenderer barGraphRendererTop = new BarGraphRenderer(4,
		 * paint2, true); mVisualizerView.addRenderer(barGraphRendererTop);
		 */
	}

	private void addCircleBarRenderer() {
		Paint paint = new Paint();
		paint.setStrokeWidth(8f);
		paint.setAntiAlias(true);
		paint.setXfermode(new PorterDuffXfermode(Mode.LIGHTEN));
		paint.setColor(Color.argb(255, 222, 92, 143));
		CircleBarRenderer circleBarRenderer = new CircleBarRenderer(paint, 32,
				true);
		mVisualizerView.addRenderer(circleBarRenderer);
	}

	private void addCircleRenderer() {
		Paint paint = new Paint();
		paint.setStrokeWidth(3f);
		paint.setAntiAlias(true);
		paint.setColor(Color.argb(255, 222, 92, 143));
		CircleRenderer circleRenderer = new CircleRenderer(paint, true);
		mVisualizerView.addRenderer(circleRenderer);
	}

	private void addLineRenderer() {
		Paint linePaint = new Paint();
		linePaint.setStrokeWidth(1f);
		linePaint.setAntiAlias(true);
		linePaint.setColor(Color.argb(88, 0, 128, 255));

		Paint lineFlashPaint = new Paint();
		lineFlashPaint.setStrokeWidth(5f);
		lineFlashPaint.setAntiAlias(true);
		lineFlashPaint.setColor(Color.argb(188, 255, 255, 255));
		LineRenderer lineRenderer = new LineRenderer(linePaint, lineFlashPaint,
				true);
		mVisualizerView.addRenderer(lineRenderer);
	}

	/**
	 * A simple class that draws waveform data received from a
	 * {@link Visualizer.OnDataCaptureListener#onWaveFormDataCapture }
	 */
	class VisualizerView1 extends View {
		private byte[] mBytes;
		private float[] mPoints;
		private Rect mRect = new Rect();
		private Paint mForePaint = new Paint();

		public VisualizerView1(Context context) {
			super(context);
			init();
		}

		private void init() {
			mBytes = null;
			mForePaint.setStrokeWidth(1f);
			mForePaint.setAntiAlias(true);
			mForePaint.setColor(Color.rgb(0, 128, 255));
		}

		public void updateVisualizer(byte[] bytes) {
			mBytes = bytes;
			invalidate();
		}

		@Override
		protected void onDraw(Canvas canvas) {
			super.onDraw(canvas);
			if (mBytes == null) {
				return;
			}
			if (mPoints == null || mPoints.length < mBytes.length * 4) {
				mPoints = new float[mBytes.length * 4];
			}
			mRect.set(0, 0, getWidth(), getHeight());
			for (int i = 0; i < mBytes.length - 1; i++) {
				mPoints[i * 4] = mRect.width() * i / (mBytes.length - 1);
				mPoints[i * 4 + 1] = mRect.height() / 2
						+ ((byte) (mBytes[i] + 128)) * (mRect.height() / 2)
						/ 128;
				mPoints[i * 4 + 2] = mRect.width() * (i + 1)
						/ (mBytes.length - 1);
				mPoints[i * 4 + 3] = mRect.height() / 2
						+ ((byte) (mBytes[i + 1] + 128)) * (mRect.height() / 2)
						/ 128;
			}
			canvas.drawLines(mPoints, mForePaint);
		}

	}

	class VisualizerView2 extends View {
		private byte[] mBytes;
		private float[] mPoints;
		private Rect mRect = new Rect();

		private Paint mForePaint = new Paint();

		public VisualizerView2(Context context) {
			super(context);
			init();
		}

		private void init() {
			mBytes = null;

			mForePaint.setStrokeWidth(1f);
			mForePaint.setAntiAlias(true);
			mForePaint.setColor(Color.rgb(0, 128, 255));
		}

		public void updateVisualizer(byte[] bytes) {
			mBytes = bytes;
			invalidate();
		}

		@Override
		protected void onDraw(Canvas canvas) {
			super.onDraw(canvas);

			if (mBytes == null) {
				return;
			}

			if (mPoints == null || mPoints.length < mBytes.length * 4) {
				mPoints = new float[mBytes.length * 4];
			}

			mRect.set(0, 0, getWidth(), getHeight());

			for (int i = 0; i < mBytes.length - 1; i++) {
				mPoints[i * 4] = mRect.width() * i / (mBytes.length - 1);
				mPoints[i * 4 + 1] = mRect.height() / 2
						+ ((byte) (mBytes[i] + 128)) * (mRect.height() / 2)
						/ 128;
				mPoints[i * 4 + 2] = mRect.width() * (i + 1)
						/ (mBytes.length - 1);
				mPoints[i * 4 + 3] = mRect.height() / 2
						+ ((byte) (mBytes[i + 1] + 128)) * (mRect.height() / 2)
						/ 128;
			}

			canvas.drawLines(mPoints, mForePaint);
		}
	}
}
